
import java.io.IOException;
import java.util.ArrayList;

public class Pere extends Thread {

    private Process process;
    //private Tampon tamponDEmission;
    private ArrayList<Tampon> tableauTamponEmission;
    private Tampon tamponDeTrace;
    private Tampon tamponDeReception;
    private HorlogeLamport horloge;
    private boolean testTirage = false;
    private int numTirage;

    public Pere(Process _process) {
        this.process = _process;
        //this.tamponDEmission = this.process.getTamponDEmission();
        tableauTamponEmission=this.process.getTableauTamponEmetteur();
        this.tamponDeTrace = this.process.getTamponDeTrace();
        this.tamponDeReception = this.process.getTamponDeReception();
        this.horloge = this.process.getHorloge();
    }

   @Override
    public void run() {
        MessageUtile message = null;
        // Boolean pour que le thread père tourne ou pour le couper
        boolean test = true;
        // Boolean pour voir si le père doit avoir un comportement normal ou seulement recevoir les messages
        boolean flagReception = true;
      
        while (test) 
        {
            System.out.println(process.getIdProcess() + " : Pere      : Attente d'un message ---------------------------> " + horloge.getCompteur());
            //message = receptionMessage();
            // On réceptionne dans un premier temps tous les messages
            while(this.process.getTamponDeReception().getTampon().size()!=0)
            {
                // Dans la fonction nous affichons le message dans la console et nous l'envoyons à la trace
                receptionMessage();
            }

            if (message.getContenu().equals("Fin")) 
            {
                System.out.println("Fermeture du thread p�re du processus " + process.getIdProcess());
                MessageUtile messageFin = new MessageUtile("Fin", 0, 0);
                // Dffuse à tous les process le message de fin. La fonction diffuse est codée dans le jalon suivant
                diffuseMessage(messageFin);
                test = false;
            }
            // Gérer la réception du message REQUEST
            else if (message.getContenu().equals("Req"))
            {
                // On ajoute la requête dans la file d'attente
                this.process.getFileDeRequete().ajoutRequete(message);
                
                //On crée un message de réponse
                MessageUtile messageReply = new MessageUtile("Rep", this.horloge.getCompteur(), this.process.getIdProcess());
                // On envoit ce message au process qui a envoyé le message Request
                envoiMessage(messageReply, message.getIdProcess());
            }
            else 
            {
                // Tant que le flag de reception est à true, le père adopte un comportement normal
                // Si le flag est à false, le thread n'envoit plus de message, il s'occupe seulement de la réception
                while(flagReception)
                {
                    //On tire le numéro aléatoire
                    int numAleatoire;
                    numAleatoire = (int) (Math.random() * 30);

                    //Si le nombre est compris entre 0 et 8, le process fait une action locale
                    if (numAleatoire >= 0 && numAleatoire < 9 ) 
                    {
                        //Action locale
                    } 
                    // Sinon si c'est compris entre 9 et 17 il envoit un message
                    else if(numAleatoire >= 9 && numAleatoire < 18 )
                    {
                        // On doit connaitre le nombre de process possible à qui le process
                        // actuel peut envoyer un message
                        // On retire un pour enlever du nombre total le process actuel
                        int nbProcess = this.process.getTableauProcess().size()-1;

                        // On tire donc un nombre au hasard compris entre 1 et nbProcess
                        // Pour savoir a qui le message sera envoyé

                        int random = (int)(Math.random() * (nbProcess-1)) + 1;

                        // Création d'un message
                        MessageUtile messageEnvoyer = new MessageUtile();
                        horloge.incrementeHorloge();
                        //Envoi du message
                        envoiMessage(messageEnvoyer, random); 
                    }
                    // Sinon si c'est compris entre 18 et 27, il il diffuse un message
                    else if(numAleatoire >= 18 && numAleatoire < 28 )
                    {
                        // Diffusion d'un message
                        int numHasard = (int) (Math.random() * 30);
                        horloge.incrementeHorloge();
                        // Si le nombre est compris entre 0 et 15, envoi d'un simple message
                        if (numHasard < 15)
                        {
                             MessageUtile messageDiffusion = new MessageUtile("Diff",horloge.getCompteur(), this.process.getIdProcess());                    
                             diffuseMessage(messageDiffusion);
                        }
                        // Sinon envoi du message request
                        else
                        {
                            MessageUtile messageRequest = new MessageUtile("REQ",horloge.getCompteur(), this.process.getIdProcess());
                            diffuseMessage(messageRequest);
                            // Passage du boolean à false pour signifier au thread père qu'il doit seulement recevoir les messages
                            flagReception = false;
                        }
                    }
                    //Sinon il ferme en envoyant un message de fin
                    else
                    {
                        System.out.println(process.getIdProcess() + " : Pere      : Fermeture du SVG -------------------------------> " + horloge.getCompteur());
                        MessageUtile messageFin = new MessageUtile("Fin", 0, 0);
                        diffuseMessage(messageFin);
                    }
                }
            }
           
        }
    }

    public void envoiMessage(Message message, int idProcessDestinataire) {
        
        int indiceTabThreadEmetteur=0;
        for (int i=0;i<this.process.getTableauEmetteur().size();i++)
        {
            if (this.process.getTableauEmetteur().get(i).getIdProcessDistant()==idProcessDestinataire)
            {
                indiceTabThreadEmetteur=i;
                i=this.process.getTableauEmetteur().size();
            }
        }
        tableauTamponEmission.get(indiceTabThreadEmetteur).setElementTampon(message);
        System.out.println(process.getIdProcess() + " : Pere      : Envoi d'un message -----------------------------> " + horloge.getCompteur());
    }

    // Fonction pour diffuser un message à tous les process interconnectés
    public void diffuseMessage(Message message)
    {
        // On parcourt le tableau de tous les emetteurs et on met le message dans chaque tampons
        for (int i=0;i<this.process.getTableauEmetteur().size();i++)
        {
             tableauTamponEmission.get(i).setElementTampon(message);
            System.out.println(process.getIdProcess() + " : Pere      : Envoi d'un message -----------------------------> " + horloge.getCompteur());
        }        
    }
    
    public MessageUtile receptionMessage() 
    {
        MessageUtile message = (MessageUtile) tamponDeReception.getElementTampon();
        horloge.incrementeHorloge(message.getEstampille());
        envoiTrace(message);
        System.out.println(process.getIdProcess() + " : Pere      : Reception d'un message -------------------------> " + horloge.getCompteur());
        //Affichage du message dans la console
        System.out.println(this.process.getIdProcess()+" Recoit le message : Contenu du message" + message.getContenu()+" Id du process depart : "+message.getIdProcess()+" Estampille :"+message.getEstampille());
        return message;
    }

    public void envoiTrace(MessageUtile message) {
        System.out.println(process.getIdProcess() + " : Pere      : Tracer --> " + message);
        Message ordre = new MessageOrdre(message.getContenu(), message.getIdProcess(), this.process.getIdProcess(), message.getEstampille(), this.horloge.getCompteur());
        tamponDeTrace.setElementTampon(ordre);
        System.out.println(process.getIdProcess() + " : Pere      : Envoi de --> " + ordre);
    }

    public void changeTestTirage() {
        this.testTirage = true;
    }

    public void setNumTirage(int num) {
        this.numTirage = num;
    }
}
